package com.sleep;

import com.alibaba.fastjson.JSON;
import lombok.extern.java.Log;
import org.apache.commons.lang3.StringUtils;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.*;
import org.hyperledger.fabric.shim.ChaincodeException;
import org.hyperledger.fabric.shim.ChaincodeStub;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Sleep-6000
 * @date 2022/5/14
 */
@Contract(
        name = "DrugContract",
        info = @Info(
                title = "Drug contract",
                description = "The hyperlegendary drug contract",
                version = "0.0.1-SNAPSHOT",
                license = @License(
                        name = "Apache 2.0 License",
                        url = "http://www.apache.org/licenses/LICENSE-2.0.html"),
                contact = @Contact(
                        email = "f.carr@example.com",
                        name = "F Carr",
                        url = "https://hyperledger.example.com")))
@Default
@Log
public class DrugContract implements ContractInterface {

    @Transaction
    public void initLedger(final Context ctx) {
        ChaincodeStub stub = ctx.getStub();
        stub.putStringState("success", "init success");
    }

    @Transaction
    public DrugResult queryDrug(final Context ctx, final String key) {
        ChaincodeStub stub = ctx.getStub();
        String drugManState = stub.getStringState(key);
        if (StringUtils.isBlank(drugManState)) {
            String errorMessage = String.format("DrugMan %s doesn't exists", key);
            System.out.println(errorMessage);
            throw new ChaincodeException(errorMessage);
        }

        DrugResult drugResult = new DrugResult();
        DrugMan drugMan = JSON.parseObject(drugManState, DrugMan.class);
        drugResult.setKey(key);
        drugResult.setDrugMan(drugMan);

        String drugTraCount = stub.getStringState(key + "DrugTra");
        if (StringUtils.isBlank(drugTraCount)) {
            return drugResult;
        }
        List<DrugTra> drugTraList = new ArrayList<>();
        for (int i = 1; i <= Integer.parseInt(drugTraCount); i++) {
            String stringState = stub.getStringState(key + "DrugTra" + i);
            DrugTra drugTra = JSON.parseObject(stringState, DrugTra.class);
            drugTraList.add(drugTra);
        }
        drugResult.setDrugTraList(drugTraList);

        String drugSelCount = stub.getStringState(key + "DrugSel");
        if (StringUtils.isBlank(drugSelCount)) {
            return drugResult;
        }
        List<DrugSel> drugSelList = new ArrayList<>();
        for (int i = 1; i <= Integer.parseInt(drugSelCount); i++) {
            String stringState = stub.getStringState(key + "DrugSel" + i);
            DrugSel drugSel = JSON.parseObject(stringState, DrugSel.class);
            drugSelList.add(drugSel);
        }
        drugResult.setDrugSelList(drugSelList);

        String drugConCount = stub.getStringState(key + "DrugCon");
        if (StringUtils.isBlank(drugSelCount)) {
            return drugResult;
        }
        List<DrugCon> drugConList = new ArrayList<>();
        for (int i = 1; i <= Integer.parseInt(drugConCount); i++) {
            String stringState = stub.getStringState(key + "DrugCon" + i);
            DrugCon drugCon = JSON.parseObject(stringState, DrugCon.class);
            drugConList.add(drugCon);
        }
        drugResult.setDrugConList(drugConList);

        return drugResult;
    }

    @Transaction
    public DrugMan createDrugMan(final Context ctx, final String key, String manName, String drugName,
                                 String batchNum, String approvalNum, String traceableCode, String mfd,
                                 String exp, String std, String other) {
        ChaincodeStub stub = ctx.getStub();
        String drugManState = stub.getStringState(key);
        if (!StringUtils.isBlank(drugManState)) {
            String errorMessage = String.format("DrugMan %s already exists", key);
            System.out.println(errorMessage);
            throw new ChaincodeException(errorMessage);
        }

        DrugMan drugMan = new DrugMan().setManName(manName)
                .setDrugName(drugName)
                .setBatchNum(batchNum)
                .setApprovalNum(approvalNum)
                .setTraceableCode(traceableCode)
                .setMfd(mfd)
                .setExp(exp)
                .setStd(std)
                .setOther(other);
        String jsonString = JSON.toJSONString(drugMan);
        stub.putStringState(key, jsonString);

        stub.setEvent("createDrugManEvent", org.apache.commons.codec.binary.StringUtils.getBytesUtf8(jsonString));
        return drugMan;
    }

    @Transaction
    public DrugTra createDrugTra(final Context ctx, final String key, String drugName, String manName,
                                 String batchNum, String traceableCode, String ostd, String selName, String other) {
        ChaincodeStub stub = ctx.getStub();
        String drugTraCount = stub.getStringState(key + "DrugTra");
        int count = 1;
        if (!StringUtils.isBlank(drugTraCount)) {
            count = Integer.parseInt(drugTraCount);
            count += 1;
        }
        stub.putStringState(key + "DrugTra", String.valueOf(count));
        DrugTra drugTra = new DrugTra().setDrugName(drugName)
                .setManName(manName)
                .setBatchNum(batchNum)
                .setTraceableCode(traceableCode)
                .setOstd(ostd)
                .setSelName(selName)
                .setOther(other);
        String jsonString = JSON.toJSONString(drugTra);
        stub.putStringState(key + "DrugTra" + count, jsonString);
        return drugTra;
    }

    @Transaction
    public DrugSel createDrugSel(final Context ctx, final String key, String selName, String drugName,
                                 String manName, String batchNum, String traceableCode, String ard, String other) {
        ChaincodeStub stub = ctx.getStub();
        String drugSelCount = stub.getStringState(key + "DrugSel");
        int count = 1;
        if (!StringUtils.isBlank(drugSelCount)) {
            count = Integer.parseInt(drugSelCount);
            count += 1;
        }
        stub.putStringState(key + "DrugSel", String.valueOf(count));

        DrugSel drugSel = new DrugSel().setSelName(selName)
                .setDrugName(drugName)
                .setManName(manName)
                .setBatchNum(batchNum)
                .setTraceableCode(traceableCode)
                .setArd(ard)
                .setOther(other);
        String jsonString = JSON.toJSONString(drugSel);
        stub.putStringState(key + "DrugSel" + count, jsonString);
        return drugSel;
    }

    @Transaction
    public DrugCon createDrugCon(final Context ctx, final String key, String selName, String consumer,
                                 String sex, String idNumber, String contact, String drugName,
                                 String cond, String batchNum, String traceableCode, String other) {
        ChaincodeStub stub = ctx.getStub();
        String drugConCount = stub.getStringState(key + "DrugCon");
        int count = 1;
        if (!StringUtils.isBlank(drugConCount)) {
            count = Integer.parseInt(drugConCount);
            count += 1;
        }
        stub.putStringState(key + "DrugCon", String.valueOf(count));

        DrugCon drugCon = new DrugCon().setSelName(selName)
                .setConsumer(consumer)
                .setSex(sex)
                .setIdNumber(idNumber)
                .setContact(contact)
                .setDrugName(drugName)
                .setCond(cond)
                .setBatchNum(batchNum)
                .setTraceableCode(traceableCode)
                .setOther(other);
        String jsonString = JSON.toJSONString(drugCon);
        stub.putStringState(key + "DrugCon" + count, jsonString);
        return drugCon;
    }

    @Transaction
    public String getState(final Context ctx, final String key) {
        ChaincodeStub stub = ctx.getStub();
        String state = stub.getStringState(key);
        if (StringUtils.isBlank(state)) {
            String errorMessage = String.format("%s doesn't exists", key);
            System.out.println(errorMessage);
            throw new ChaincodeException(errorMessage);
        }
        return state;
    }

    @Transaction
    public String setState(final Context ctx, final String key, String val) {
        ChaincodeStub stub = ctx.getStub();
        stub.putStringState(key, val);
        return val;
    }

    @Override
    public void beforeTransaction(Context ctx) {
        log.info("*************************************** beforeTransaction ***************************************");
    }

    @Override
    public void afterTransaction(Context ctx, Object result) {
        log.info("*************************************** afterTransaction ***************************************");
        System.out.println("result --------> " + result);
    }
}
